// <com.woyouqiu.Copyright>
// --------------------------------------------------------------
// <copyright>上海有求网络科技有限公司 2015</copyright>
// <Solution>Vecen.BangChuang</Solution>
// <Project>Vecen.BangChuang.Application</Project>
// <FileName>WalletAppService.cs</FileName>
// <CreateTime>2017-05-16 15:23</CreateTime>
// <Author>何苗</Author>
// <Email>hemiao@woyouqiu.com</Email>
// <log date="2017-05-16 15:23" version="00001">创建</log>
// --------------------------------------------------------------
// </com.woyouqiu.Copyright>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Runtime.Session;
using Abp.UI;
using Microsoft.AspNetCore.Identity;
using Vecen.BangChuang.Authorization.Accounts.Dto;
using Vecen.BangChuang.Authorization.Users;
using Vecen.BangChuang.BangChuang.Common;
using Vecen.BangChuang.BangChuang.DomainServices.Agents;
using Vecen.BangChuang.BangChuang.DomainServices.Common;
using Vecen.BangChuang.BangChuang.Wallets.Dtos;

namespace Vecen.BangChuang.BangChuang.Wallets {

    /// <summary>
    /// 钱包信息
    /// </summary>
    [AbpAuthorize()]
    public class WalletAppService: BangChuangAppServiceBase, IWalletAppService {

        private readonly ValidationCodeDomainService _validationCodeDomainService;
        private readonly IRepository<PointInfo> _pointInfoRepository;
        private readonly IRepository<BankCard> _bankCardRepository;
        private readonly IRepository<PointWithdraw> _pointWithdrawRepository;
        private readonly AgentDomainService _agentDomainService;
        private readonly IRepository<BankType, string> _bankTypeRepository;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="validationCodeDomainService"></param>
        /// <param name="pointInfoRepository"></param>
        /// <param name="bankCardRepository"></param>
        /// <param name="pointWithdrawRepository"></param>
        /// <param name="agentDomainService"></param>
        /// <param name="bankTypeRepository"></param>
        public WalletAppService(ValidationCodeDomainService validationCodeDomainService,
            IRepository<PointInfo> pointInfoRepository,
            IRepository<BankCard> bankCardRepository,
            IRepository<PointWithdraw> pointWithdrawRepository,
            AgentDomainService agentDomainService,
            IRepository<BankType, string> bankTypeRepository) {
            _validationCodeDomainService = validationCodeDomainService;
            _pointInfoRepository = pointInfoRepository;
            _bankCardRepository = bankCardRepository;
            _pointWithdrawRepository = pointWithdrawRepository;
            _agentDomainService = agentDomainService;
            _bankTypeRepository = bankTypeRepository;
        }

        /// <summary>
        /// 获得钱包信息
        /// </summary>
        /// <returns></returns>
        public async Task<WalletOutDto> GetWalletInfoAsync() {
            var pointInfos = await Task.Run(() => _pointInfoRepository.GetAll()
                .Where(c => c.UserId == AbpSession.UserId)
                .ToList());
            var outdto = new WalletOutDto();
            outdto.BankCardCount = await _bankCardRepository.CountAsync(c => c.UserId == AbpSession.UserId);
            var user = await UserManager.GetUserByIdAsync(AbpSession.GetUserId());
            outdto.IsSetWithdrawPassword = !user.WithdrawPassword.IsNullOrEmpty();
            outdto.TotalPoint = pointInfos.Sum(c => c.TotalPoint);
            outdto.Point = pointInfos.Sum(c => c.SurplusPoint);
            return outdto;
        }

        /// <summary>
        /// 添加银行帐号
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task SaveBankCardAsync(BankCardInputDto input) {
            var entity = input.MapTo<BankCard>();
            entity.UserId = AbpSession.GetUserId();
            entity.IsDefault = false;
            await _bankCardRepository.InsertAndGetIdAsync(entity);
        }

        /// <summary>
        /// 获取当前用户的所有银行卡
        /// </summary>
        /// <returns></returns>
        public async Task<ListResultDto<BankCardListDto>> GetSelfBankCardsAsync() {
            var list = await Task.Run(() => _bankCardRepository.GetAll()
                .Where(c => c.UserId == AbpSession.UserId)
                .ToList());
            return new ListResultDto<BankCardListDto>(list.MapTo<List<BankCardListDto>>());
        }

        /// <summary>
        /// 更新银行卡信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateBankCardAsync(BankCardInputDto input) {
            var entity = await _bankCardRepository.FirstOrDefaultAsync(input.Id);
            if(entity == null || entity.UserId != AbpSession.UserId) {
                throw new UserFriendlyException("请求失败!", "记录不存在或不是你的银行卡记录,无法修改!");
            }
            entity = input.MapTo<BankCard>();
            await _bankCardRepository.InsertOrUpdateAndGetIdAsync(entity);
        }

        /// <summary>
        /// 删除银行卡
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteBankCardAsync(int id) {
            var entity = await _bankCardRepository.FirstOrDefaultAsync(id);
            if(entity == null || entity.UserId != AbpSession.UserId) {
                throw new UserFriendlyException("请求失败!", "记录不存在或不是你的银行卡记录,无法修改!");
            }
            await _bankCardRepository.DeleteAsync(id);
        }

        /// <summary>
        /// 申请提现
        /// </summary>
        /// <returns></returns>
        public async Task ApplyWithdrawAsync(ApplyWithdrawInputDto input) {
            var user = await UserManager.GetUserByIdAsync(AbpSession.GetUserId());
            var passwordValidate =
                new PasswordHasher<User>().VerifyHashedPassword(user, user.WithdrawPassword, input.WithdrawPassword);
            if(passwordValidate == PasswordVerificationResult.Failed) {
                throw new UserFriendlyException("提现失败!", "提现密码不正确!");
            }

            var agent = await _agentDomainService.GetByUserIdAsync(AbpSession.GetUserId());
            if(agent == null) {
                throw new UserFriendlyException("申请失败", "您不是店长.不能进行此操作!");
            }

            var entity = new PointWithdraw();
            entity.UserId = AbpSession.GetUserId();
            entity.AgentId = agent.Id;
            entity.ApplyTime = DateTime.Now;
            entity.BankCardId = input.BankCardId;
            entity.Point = input.ApplyPoint;
            entity.Status = PointWithdrawStatus.Apply;
            await _pointWithdrawRepository.InsertOrUpdateAndGetIdAsync(entity);
        }

        /// <summary>
        /// 获得所有提现记录
        /// </summary>
        /// <returns></returns>
        public async Task<PagedResultDto<WithdrawListOutDto>> GetAllWithdrawAsync(GetAllWithdrawInputDto input) {
            var query = _pointWithdrawRepository.GetAll()
                .Where(c => c.UserId == AbpSession.UserId)
                .WhereIf(input.StartTime.HasValue, c => c.ApplyTime >= input.StartTime)
                .WhereIf(input.EndTime.HasValue, c => c.ApplyTime <= input.EndTime)
                .WhereIf(input.Status.HasValue, c => c.Status == input.Status);
            var total = await Task.Run(() => query.Count());
            var paged = await Task.Run(() => query.OrderBy(input.Sorting).PageBy(input).ToList());
            return new PagedResultDto<WithdrawListOutDto>(total, paged.MapTo<List<WithdrawListOutDto>>());
        }

        /// <summary>
        /// 删除提现申请
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteWithdrawAppyAsync(int id) {
            var entity = await _pointWithdrawRepository.FirstOrDefaultAsync(id);
            if(entity.Status != PointWithdrawStatus.Apply) {
                throw new UserFriendlyException("删除失败", "提现申请已经审核通过或已付款,不能删除!");
            }
            await _pointWithdrawRepository.DeleteAsync(id);
        }

        /// <summary>
        /// 设置提现密码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize()]
        public async Task SetWithdrawPassword(WithdrawPasswordSetInput input) {
            var user = await UserManager.GetUserByIdAsync(AbpSession.GetUserId());
            if(!user.WithdrawPassword.IsNullOrEmpty()) {
                throw new UserFriendlyException("请求失败!", "您已经设置过提现密码了.");
            }

            if(input.NewPassword.IsNullOrWhiteSpace()) {
                throw new UserFriendlyException("请求失败!", "提现密码不能为空.");
            }
            if(!await _validationCodeDomainService.ValidationAsync(user.PhoneNumber, input.ValidationCode,
                ValidationCodeType.SetWithdrawPassword)) {
                throw new UserFriendlyException("请求失败!", "验证码不正确.");
            }

            user.WithdrawPassword = new PasswordHasher<User>().HashPassword(user, input.NewPassword);
            await UserManager.UpdateAsync(user);
        }

        /// <summary>
        /// 修改提现密码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize()]
        public async Task ChangeWithdrawPassword(WithdrawPasswordChangeInput input) {
            var user = await UserManager.GetUserByIdAsync(AbpSession.GetUserId());

            if(input.NewPassword.IsNullOrWhiteSpace()) {
                throw new UserFriendlyException("请求失败!", "新的提现密码不能为空.");
            }
            if(new PasswordHasher<User>().HashPassword(user, input.OldPassword) != user.WithdrawPassword) {
                throw new UserFriendlyException("请求失败!", "原提现密码不正确.");
            }
            user.WithdrawPassword = new PasswordHasher<User>().HashPassword(user, input.NewPassword);
            await UserManager.UpdateAsync(user);
        }

        /// <summary>
        /// 获得银行类型列表
        /// </summary>
        /// <returns></returns>
        public async Task<ListResultDto<BankTypeListDto>> GetBankTypesAsync() {
            var list = await Task.Run(() => _bankTypeRepository.GetAll()
                .Where(c => c.IsActive)
                .Select(c => new BankTypeListDto() {BankCode = c.Id, BankName = c.BankName})
                .ToList());

            return new ListResultDto<BankTypeListDto>(list);
        }
    }
}